// http://download.intel.com/design/chipsets/datashts/29056601.pdf
// IO APIC (输入/输出高级可编程中断控制器) 实现
// 参考 Intel I/O APIC 数据手册

use crate::cpu::{apic, global_pointers::acpi_enabled};
use std::sync::{Mutex, MutexGuard};

// 是否启用详细日志
const IOAPIC_LOG_VERBOSE: bool = false;

// IO APIC 寄存器选择器和数据窗口偏移量
const IOREGSEL: u32 = 0;       // 寄存器选择器地址偏移
const IOWIN: u32 = 0x10;       // I/O 窗口地址偏移

// IO APIC 支持的中断请求数量
const IOAPIC_IRQ_COUNT: usize = 24;

// 中断路由表寄存器范围
const IOAPIC_FIRST_IRQ_REG: u32 = 0x10;  // 第一个中断路由表寄存器
const IOAPIC_LAST_IRQ_REG: u32 = 0x10 + 2 * IOAPIC_IRQ_COUNT as u32;  // 最后一个中断路由表寄存器

// IO APIC ID (必须与 seabios 中的值匹配)
const IOAPIC_ID: u32 = 0;

// IO APIC 配置标志位
pub const IOAPIC_CONFIG_TRIGGER_MODE_LEVEL: u32 = 1 << 15;  // 电平触发模式
const IOAPIC_CONFIG_MASKED: u32 = 1 << 16;                  // 中断屏蔽
const IOAPIC_CONFIG_DELIVS: u32 = 1 << 12;                  // 中断已送达
const IOAPIC_CONFIG_REMOTE_IRR: u32 = 1 << 14;              // 远程 IRR 位
const IOAPIC_CONFIG_READONLY_MASK: u32 =                    // 只读位掩码
    IOAPIC_CONFIG_REMOTE_IRR | IOAPIC_CONFIG_DELIVS | 0xFFFE0000;

// 中断传递模式
const IOAPIC_DELIVERY_FIXED: u8 = 0;                   // 固定模式
const IOAPIC_DELIVERY_LOWEST_PRIORITY: u8 = 1;         // 最低优先级模式
const _IOAPIC_DELIVERY_NMI: u8 = 4;                    // 不可屏蔽中断
const _IOAPIC_DELIVERY_INIT: u8 = 5;                   // 初始化中断

// 中断传递模式的中文描述
const DELIVERY_MODES: [&str; 8] = [
    "固定模式 (0)",
    "最低优先级 (1)",
    "系统管理中断 (2)",
    "保留 (3)",
    "不可屏蔽中断 (4)",
    "初始化中断 (5)",
    "保留 (6)",
    "外部中断 (7)",
];

// 目标模式的中文描述
const DESTINATION_MODES: [&str; 2] = ["物理模式", "逻辑模式"];

// 结构体大小常量 (需与 cpu.js 保持同步)
#[allow(dead_code)]
const IOAPIC_STRUCT_SIZE: usize = 4 * 52;

// 内存布局断言 (JavaScript 代码依赖于此布局)
const _: () = assert!(std::mem::offset_of!(Ioapic, ioredtbl_destination) == 24 * 4);
const _: () = assert!(std::mem::offset_of!(Ioapic, ioregsel) == 48 * 4);
const _: () = assert!(std::mem::offset_of!(Ioapic, irq_value) == 51 * 4);
const _: () = assert!(std::mem::size_of::<Ioapic>() == IOAPIC_STRUCT_SIZE);

/// IO APIC 结构体定义
/// 
/// 表示一个 I/O 高级可编程中断控制器，用于管理系统中的 I/O 中断
#[repr(C)]
struct Ioapic {
    ioredtbl_config: [u32; IOAPIC_IRQ_COUNT],      // 中断路由表配置寄存器
    ioredtbl_destination: [u32; IOAPIC_IRQ_COUNT], // 中断路由表目标寄存器
    ioregsel: u32,                                 // 寄存器选择器
    ioapic_id: u32,                                // IO APIC ID
    irr: u32,                                      // 中断请求寄存器
    irq_value: u32,                                // 中断值状态
}

/// 全局 IO APIC 实例 (使用互斥锁保护以确保线程安全)
static IOAPIC: Mutex<Ioapic> = Mutex::new(Ioapic {
    ioredtbl_config: [IOAPIC_CONFIG_MASKED; IOAPIC_IRQ_COUNT], // 默认屏蔽所有中断
    ioredtbl_destination: [0; IOAPIC_IRQ_COUNT],               // 默认目标
    ioregsel: 0,                                               // 默认选择器
    ioapic_id: IOAPIC_ID,                                      // 默认 ID
    irr: 0,                                                    // 初始无中断请求
    irq_value: 0,                                              // 初始无中断值
});

/// 获取 IO APIC 实例的互斥锁保护引用
/// 
/// # 返回值
/// 一个 IO APIC 实例的互斥锁保护引用
fn get_ioapic() -> MutexGuard<'static, Ioapic> { IOAPIC.try_lock().unwrap() }

/// 获取 IO APIC 的内存地址 (导出到 JavaScript)
/// 
/// # 返回值
/// IO APIC 的内存地址
#[no_mangle]
pub fn get_ioapic_addr() -> u32 { &raw mut *get_ioapic() as u32 }

/// 远程中断结束确认 (公共 API)
/// 
/// 用于确认远程中断已完成处理
/// 
/// # 参数
/// - `apic`: APIC 实例的可变引用
/// - `vector`: 中断向量号
pub fn remote_eoi(apic: &mut apic::Apic, vector: u8) {
    remote_eoi_internal(&mut get_ioapic(), apic, vector);
}

/// 内部远程中断结束确认函数
/// 
/// 查找与指定向量匹配的中断，并清除其远程 IRR 位
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `apic`: APIC 实例的可变引用
/// - `vector`: 中断向量号
fn remote_eoi_internal(ioapic: &mut Ioapic, apic: &mut apic::Apic, vector: u8) {
    // 遍历所有可能的中断源
    for i in 0..IOAPIC_IRQ_COUNT as u8 {
        let config = ioapic.ioredtbl_config[i as usize];

        // 如果找到匹配的向量并且远程 IRR 位被设置
        if (config & 0xFF) as u8 == vector && config & IOAPIC_CONFIG_REMOTE_IRR != 0 {
            dbg_log!("Clear remote IRR for irq={:x}", i);
            ioapic.ioredtbl_config[i as usize] &= !IOAPIC_CONFIG_REMOTE_IRR;
            check_irq(ioapic, apic, i);
        }
    }
}

/// 检查并处理中断
/// 
/// 处理指定中断请求，根据配置进行路由
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `apic`: APIC 实例的可变引用
/// - `irq`: 中断请求号
fn check_irq(ioapic: &mut Ioapic, apic: &mut apic::Apic, irq: u8) {
    let mask = 1 << irq;

    // 如果该中断请求位未设置，则无需处理
    if ioapic.irr & mask == 0 {
        return;
    }

    // 获取该中断的配置
    let config = ioapic.ioredtbl_config[irq as usize];

    // 如果中断未被屏蔽
    if config & IOAPIC_CONFIG_MASKED == 0 {
        let delivery_mode = ((config >> 8) & 7) as u8;
        let destination_mode = ((config >> 11) & 1) as u8;
        let vector = (config & 0xFF) as u8;
        let destination = (ioapic.ioredtbl_destination[irq as usize] >> 24) as u8;
        let is_level = config & IOAPIC_CONFIG_TRIGGER_MODE_LEVEL == IOAPIC_CONFIG_TRIGGER_MODE_LEVEL;

        // 处理不同的触发模式
        if config & IOAPIC_CONFIG_TRIGGER_MODE_LEVEL == 0 {
            // 边缘触发：清除中断请求
            ioapic.irr &= !mask;
        }
        else {
            // 电平触发：设置远程 IRR 位
            ioapic.ioredtbl_config[irq as usize] |= IOAPIC_CONFIG_REMOTE_IRR;

            // 如果远程 IRR 已经设置，则不路由
            if config & IOAPIC_CONFIG_REMOTE_IRR != 0 {
                dbg_log!("No route: level interrupt and remote IRR still set");
                return;
            }
        }

        // 路由支持的中断传递模式
        if delivery_mode == IOAPIC_DELIVERY_FIXED
            || delivery_mode == IOAPIC_DELIVERY_LOWEST_PRIORITY
        {
            apic::route(
                apic,
                vector,
                delivery_mode,
                is_level,
                destination,
                destination_mode,
            );
        }
        else {
            dbg_assert!(false, "TODO");
        }

        // 清除已送达标志
        ioapic.ioredtbl_config[irq as usize] &= !IOAPIC_CONFIG_DELIVS;
    }
}

/// 设置中断请求 (公共 API)
/// 
/// 触发指定的中断请求
/// 
/// # 参数
/// - `i`: 中断请求号
pub fn set_irq(i: u8) { set_irq_internal(&mut get_ioapic(), &mut apic::get_apic(), i) }

/// 内部设置中断请求函数
/// 
/// 处理中断请求的设置逻辑
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `apic`: APIC 实例的可变引用
/// - `i`: 中断请求号
fn set_irq_internal(ioapic: &mut Ioapic, apic: &mut apic::Apic, i: u8) {
    // 检查中断请求号是否有效
    if i as usize >= IOAPIC_IRQ_COUNT {
        dbg_assert!(false, "Bad irq: {}", i);
        return;
    }

    let mask = 1 << i;

    // 如果该中断尚未设置
    if ioapic.irq_value & mask == 0 {
        if IOAPIC_LOG_VERBOSE {
            dbg_log!("apic set irq {}", i);
        }

        // 设置中断值
        ioapic.irq_value |= mask;

        // 获取中断配置
        let config = ioapic.ioredtbl_config[i as usize];
        // 如果是边缘触发且被屏蔽，则不处理
        if config & (IOAPIC_CONFIG_TRIGGER_MODE_LEVEL | IOAPIC_CONFIG_MASKED)
            == IOAPIC_CONFIG_MASKED
        {
            return;
        }

        // 设置中断请求位
        ioapic.irr |= mask;

        // 检查并处理中断
        check_irq(ioapic, apic, i);
    }
}

/// 清除中断请求 (公共 API)
/// 
/// 清除指定的中断请求
/// 
/// # 参数
/// - `i`: 中断请求号
pub fn clear_irq(i: u8) { clear_irq_internal(&mut get_ioapic(), i) }

/// 内部清除中断请求函数
/// 
/// 处理中断请求的清除逻辑
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `i`: 中断请求号
fn clear_irq_internal(ioapic: &mut Ioapic, i: u8) {
    // 检查中断请求号是否有效
    if i as usize >= IOAPIC_IRQ_COUNT {
        dbg_assert!(false, "Bad irq: {}", i);
        return;
    }

    let mask = 1 << i;

    // 如果该中断已设置
    if ioapic.irq_value & mask == mask {
        // 清除中断值
        ioapic.irq_value &= !mask;

        // 获取中断配置
        let config = ioapic.ioredtbl_config[i as usize];
        // 如果是电平触发，同时清除中断请求
        if config & IOAPIC_CONFIG_TRIGGER_MODE_LEVEL != 0 {
            ioapic.irr &= !mask;
        }
    }
}

/// 从 IO APIC 寄存器读取 32 位值 (公共 API)
/// 
/// 读取 IO APIC 寄存器的内容
/// 
/// # 参数
/// - `addr`: 寄存器地址
/// 
/// # 返回值
/// 寄存器的 32 位值
pub fn read32(addr: u32) -> u32 {
    // 检查 ACPI 是否启用
    if unsafe { !*acpi_enabled } {
        return 0;
    }
    read32_internal(&mut get_ioapic(), addr)
}

/// 内部读取 IO APIC 寄存器函数
/// 
/// 根据地址读取 IO APIC 寄存器的内容
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `addr`: 寄存器地址
/// 
/// # 返回值
/// 寄存器的 32 位值
fn read32_internal(ioapic: &mut Ioapic, addr: u32) -> u32 {
    match addr {
        // 读取寄存器选择器
        IOREGSEL => ioapic.ioregsel,
        // 通过 I/O 窗口读取寄存器
        IOWIN => match ioapic.ioregsel {
            // 读取 ID 寄存器
            0 => {
                dbg_log!("IOAPIC Read id");
                ioapic.ioapic_id << 24
            },
            // 读取版本寄存器
            1 => {
                dbg_log!("IOAPIC Read version");
                0x11 | (IOAPIC_IRQ_COUNT as u32 - 1) << 16
            },
            // 读取仲裁 ID 寄存器
            2 => {
                dbg_log!("IOAPIC Read arbitration id");
                ioapic.ioapic_id << 24
            },
            // 读取中断路由表寄存器
            IOAPIC_FIRST_IRQ_REG..IOAPIC_LAST_IRQ_REG => {
                let irq = ((ioapic.ioregsel - IOAPIC_FIRST_IRQ_REG) >> 1) as u8;
                let index = ioapic.ioregsel & 1;

                if index != 0 {
                    // 读取目标寄存器
                    let value = ioapic.ioredtbl_destination[irq as usize];
                    dbg_log!("IOAPIC Read destination irq={:x} -> {:08x}", irq, value);
                    value
                }
                else {
                    // 读取配置寄存器
                    let value = ioapic.ioredtbl_config[irq as usize];
                    dbg_log!("IOAPIC Read config irq={:x} -> {:08x}", irq, value);
                    value
                }
            },
            // 无效的寄存器
            reg => {
                dbg_assert!(false, "IOAPIC register read outside of range {:x}", reg);
                0
            },
        },
        // 未对齐或超出范围的内存读取
        _ => {
            dbg_assert!(false, "Unaligned or oob IOAPIC memory read: {:x}", addr);
            0
        },
    }
}

/// 向 IO APIC 寄存器写入 32 位值 (公共 API)
/// 
/// 向 IO APIC 寄存器写入数据
/// 
/// # 参数
/// - `addr`: 寄存器地址
/// - `value`: 要写入的 32 位值
pub fn write32(addr: u32, value: u32) {
    // 检查 ACPI 是否启用
    if unsafe { !*acpi_enabled } {
        return;
    }
    write32_internal(&mut get_ioapic(), &mut apic::get_apic(), addr, value)
}

/// 内部写入 IO APIC 寄存器函数
/// 
/// 根据地址向 IO APIC 寄存器写入数据
/// 
/// # 参数
/// - `ioapic`: IO APIC 实例的可变引用
/// - `apic`: APIC 实例的可变引用
/// - `addr`: 寄存器地址
/// - `value`: 要写入的 32 位值
fn write32_internal(ioapic: &mut Ioapic, apic: &mut apic::Apic, addr: u32, value: u32) {
    match addr {
        // 写入寄存器选择器
        IOREGSEL => ioapic.ioregsel = value,
        // 通过 I/O 窗口写入寄存器
        IOWIN => match ioapic.ioregsel {
            // 写入 ID 寄存器
            0 => ioapic.ioapic_id = (value >> 24) & 0x0F,
            // 版本和仲裁 ID 寄存器通常是只读的
            1 | 2 => {
                dbg_log!("IOAPIC Invalid write: {}", ioapic.ioregsel);
            },
            // 写入中断路由表寄存器
            IOAPIC_FIRST_IRQ_REG..IOAPIC_LAST_IRQ_REG => {
                let irq = ((ioapic.ioregsel - IOAPIC_FIRST_IRQ_REG) >> 1) as u8;
                let index = ioapic.ioregsel & 1;

                if index != 0 {
                    // 写入目标寄存器
                    dbg_log!(
                        "Write destination {:08x} irq={:x} dest={:02x}",
                        value,
                        irq,
                        value >> 24
                    );
                    ioapic.ioredtbl_destination[irq as usize] = value & 0xFF000000;
                }
                else {
                    // 写入配置寄存器，保留只读位
                    let old_value = ioapic.ioredtbl_config[irq as usize] as u32;
                    ioapic.ioredtbl_config[irq as usize] = (value & !IOAPIC_CONFIG_READONLY_MASK)
                        | (old_value & IOAPIC_CONFIG_READONLY_MASK);

                    // 解析配置值的各个字段
                    let vector = value & 0xFF;
                    let delivery_mode = (value >> 8) & 7;
                    let destination_mode = (value >> 11) & 1;
                    let is_level = (value >> 15) & 1;
                    let disabled = (value >> 16) & 1;

                    dbg_log!(
                            "Write config {:08x} irq={:x} vector={:02x} deliverymode={} destmode={} is_level={} disabled={}",
                            value,
                            irq,
                            vector,
                            DELIVERY_MODES[delivery_mode as usize],
                            DESTINATION_MODES[destination_mode as usize],
                            is_level,
                            disabled
                        );

                    // 检查并处理该中断
                    check_irq(ioapic, apic, irq);
                }
            },
            // 无效的寄存器
            reg => {
                dbg_assert!(
                    false,
                    "IOAPIC register write outside of range {:x} <- {:x}",
                    reg,
                    value
                )
            },
        },
        // 未对齐或超出范围的内存写入
        _ => {
            dbg_assert!(
                false,
                "Unaligned or oob IOAPIC memory write: {:x} <- {:x}",
                addr,
                value
            )
        },
    }
}
